package com.cyj.dream.core.handler;

import com.cyj.dream.core.aspect.annotation.ResponseResult;
import com.cyj.dream.core.util.pojo.ApiResult;
import com.cyj.dream.core.util.pojo.ErrorResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @Description: 响应返回值拦截器方法返回值拦截处理器 1.实现ResponseBodyAdvice重写两个方法 2.添加@ControllerAdvice注解
 * @BelongsProject: DreamChardonnay
 * @BelongsPackage: com.cyj.dream.core.handler
 * @Author: ChenYongJia
 * @CreateTime: 2021-09-26 11:07
 * @Email: chen87647213@163.com
 * @Version: 1.0
 */
@Slf4j
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {

    /**
     * 标记名称
     * ControllerAdvice 1.全局异常处理 （@ExceptionHandler）
     * 2.全局数据绑定 （@InitBinder）
     * 3.全局数据预处理 （@ModelAttribute）
     */
    public static final String RESPONSE_RESULT_ANN = "RESPONSE-RESULT-ANN";


    /**
     * 判断是否要执行 beforeBodyWrite 方法，true为执行，false不执行，有注解标记的时候处理返回值
     *
     * @param arg0
     * @param arg1
     * @return
     */
    @Override
    public boolean supports(MethodParameter arg0, Class<? extends HttpMessageConverter<?>> arg1) {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sra.getRequest();
        // 判断请求是否有包装标记
        ResponseResult responseResultAnn = (ResponseResult) request.getAttribute(RESPONSE_RESULT_ANN);
        return responseResultAnn == null ? false : true;
    }


    /**
     * 对返回值做包装处理，如果属于异常结果，则需要再包装
     *
     * @param body
     * @param arg1
     * @param arg2
     * @param arg3
     * @param arg4
     * @param arg5
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter arg1, MediaType arg2,
                                  Class<? extends HttpMessageConverter<?>> arg3, ServerHttpRequest arg4, ServerHttpResponse arg5) {
        log.info("-----------------返回值未作处理前为：{}", body);
        /**
         * instanceof运算符用法
         * 运算符是双目运算符,左面的操作元是一个对象,右面是一个类.当
         * 左面的对象是右面的类创建的对象时,该运算符运算的结果是true,否则是false
         */
        if (body instanceof ErrorResult) {
            ErrorResult error = (ErrorResult) body;
            log.error("-----------------返回异常结果信息为：{}", ApiResult.failAndMessage(error.getCode(), error.getMessage()));
            return ApiResult.failAndMessage(error.getCode(), error.getMessage());
        } else if (body instanceof ApiResult) {
            // 当控制器以这种形式===>return ApiResult.fail(ResultCode.FAILURE);返回时触发
            log.info("-----------------返回结果统一信息处理为：{}", (ApiResult) body);
            return (ApiResult) body;
        }
        // 当控制器直接返回成功的 data 时触发
        log.info("-----------------返回成功信息处理为：{}", ApiResult.successAndData(body));
        return ApiResult.successAndData(body);
    }

}
